//*******************************************************************
//	created:	5:4:2011   22:03
//	filename: 	base64helper.cpp
//	author:		tiamo
//	purpose:	base64 helper
//*******************************************************************

#include "stdafx.h"
#include "base64helper.h"

namespace base64
{
	//
	// encode
	//
	UniString encode(void const* inputBuffer, uint32_t inputLength)
	{
		static wchar_t table64[]											= L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
		uint8_t const* inputChar											= static_cast<uint8_t const*>(inputBuffer);
		UniString retData;

		while(inputLength)
		{
			char iBuf[3]													= {0};
			wchar_t oBuf[4]													= {0};
			uint32_t inputparts												= 0;
			for(uint32_t i = 0; i < 3; i++) 
			{ 
				if(inputLength) 
				{
					inputparts												+= 1;
					iBuf[i]													= *inputChar;
					inputChar												+= 1;
					inputLength												-= 1;
				}
				else
				{
					iBuf[i]													= 0;
				}
			}

			oBuf[0]															= table64[(iBuf [0] & 0xfc) >> 2];
			oBuf[1]															= table64[((iBuf [0] & 0x03) << 4) | ((iBuf [1] & 0xf0) >> 4)];
			oBuf[2]															= inputparts > 1 ? table64[((iBuf [1] & 0x0f) << 2) | ((iBuf [2] & 0xc0) >> 6)] : L'=';
			oBuf[3]															= inputparts > 2 ? table64[iBuf [2] & 0x3f] : L'=';

			retData.append(oBuf, 4);
		}

		return retData;
	}

	//
	// decode
	//
	uint32_t decode(UniString const& inputString, void* outputBuffer, uint32_t& outputLength)
	{
		static wchar_t table64[]											= L"|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
		wchar_t const* inputChar											= inputString.c_str();
		uint32_t inputLength												= static_cast<uint32_t>(inputString.length());
		uint32_t retLength													= 0;

		while(inputLength)
		{
			char iBuf[4]													= {0};
			char oBuf[3]													= {0};
			uint32_t inputParts												= 0;
			for(uint32_t i = 0; i < 4; i++) 
			{
				if(inputLength) 
				{
					inputParts												+= 1;
					wchar_t v												= *inputChar;
					v														= v < 43 || v > 122 ? 0 : table64[v - 43];
					if(v)
						v													= v == L'$' ? 0 : v - 61;
					iBuf[i]													= v ? v - 1 : 0;
					inputChar												+= 1;
					inputLength												-= 1;
				}
				else
				{
					iBuf[i]													= 0;
					break;
				}
			}

			oBuf[0]															= (iBuf[0] << 2 | iBuf[1] >> 4);
			oBuf[1]															= (iBuf[1] << 4 | iBuf[2] >> 2);
			oBuf[2]															= (((iBuf[2] << 6) & 0xc0) | iBuf[3]);

			if(outputLength < retLength + inputParts - 1)
				break;

			memcpy(static_cast<uint8_t*>(outputBuffer) + retLength, oBuf,  inputParts - 1);
			retLength														+= inputParts - 1;
		}

		outputLength														= retLength;
		return inputLength;
	}
}
